package tasknow.utils;

import java.util.Calendar;

public class Task {

	// @author A0096638M
	// A Task class contains a description, a start date and time, and end date
	// and time for each task

	// Private methods and variables
	private String _description = null;
	private Calendar _startCalendar = null;
	private Calendar _endCalendar = null;
	private Constants.TASK_STATUS _taskStatus = Constants.TASK_STATUS.INCOMPLETE;

	private void setDescription(String description) {
		this._description = description;
	}

	private void setStartCalendar(Calendar start_calendar) {
		this._startCalendar = start_calendar;
	}

	private void setEndCalendar(Calendar end_calendar) {
		this._endCalendar = end_calendar;
	}

	private void setTaskStatus(boolean taskStatus) {
		if (taskStatus) {
			this._taskStatus = Constants.TASK_STATUS.COMPLETED;
		} else {
			this._taskStatus = Constants.TASK_STATUS.INCOMPLETE;
		}
	}

	// Public methods
	public Task() {

	}

	public Task(String description) {
		this.setDescription(description);
	}

	public Task(String description, Calendar start_calendar,
			Calendar end_calendar) {
		this.setDescription(description);
		this.setStartCalendar(start_calendar);
		this.setEndCalendar(end_calendar);
	}

	public Task(String description, Calendar start_calendar,
			Calendar end_calendar, boolean taskStatus) {
		this.setDescription(description);
		this.setStartCalendar(start_calendar);
		this.setEndCalendar(end_calendar);
		this.setTaskStatus(taskStatus);
	}

	public void removeStartDate() {
		this._startCalendar.set(Calendar.YEAR, Constants.DEFAULT_YEAR);
		this._startCalendar.set(Calendar.HOUR_OF_DAY, Constants.DEFAULT_HOUR);
		this._startCalendar.set(Calendar.MINUTE, Constants.DEFAULT_MINUTE);
	}

	public void removeEndDate() {
		this._endCalendar.set(Calendar.YEAR, Constants.DEFAULT_YEAR);
		this._endCalendar.set(Calendar.HOUR_OF_DAY, Constants.DEFAULT_HOUR);
		this._endCalendar.set(Calendar.MINUTE, Constants.DEFAULT_MINUTE);

		if (_startCalendar != null) {
			this._startCalendar.set(Calendar.YEAR, Constants.DEFAULT_YEAR);
			this._startCalendar.set(Calendar.HOUR_OF_DAY,
					Constants.DEFAULT_HOUR);
			this._startCalendar.set(Calendar.MINUTE, Constants.DEFAULT_MINUTE);
		}
	}

	public void modifyDescription(String description) {
		this._description = description;
	}

	public void modifyStartCalendar(Calendar start_calendar) {
		this._startCalendar = start_calendar;
	}

	public void modifyEndCalendar(Calendar end_calendar) {
		this._endCalendar = end_calendar;
	}

	public void modifyStartDateTime(int[] dateInt, int[] timeInt) {
		if (this._startCalendar == null) {
			this._startCalendar = Calendar.getInstance();
			this._startCalendar.clear();
			this._startCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY],
					timeInt[Constants.HOUR], timeInt[Constants.MINUTE]);
		} else {
			this._startCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY],
					timeInt[Constants.HOUR], timeInt[Constants.MINUTE]);
		}
	}

	public void modifyStartDate(int[] dateInt) {
		if (this._startCalendar == null) {
			this._startCalendar = Calendar.getInstance();
			this._startCalendar.set(Calendar.HOUR_OF_DAY, 0);
			this._startCalendar.clear(Calendar.MINUTE);
			this._startCalendar.clear(Calendar.SECOND);
			this._startCalendar.clear(Calendar.MILLISECOND);
			this._startCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY]);
		} else {
			this._startCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY]);
		}
	}

	public void modifyStartTime(int[] timeInt) {
		if (this._startCalendar == null) {
			this._startCalendar = Calendar.getInstance();
			this._startCalendar.clear(Calendar.YEAR);
			this._startCalendar.clear(Calendar.MONTH);
			this._startCalendar.clear(Calendar.DAY_OF_MONTH);
			this._startCalendar.set(Calendar.HOUR_OF_DAY,
					timeInt[Constants.HOUR]);
			this._startCalendar
			.set(Calendar.MINUTE, timeInt[Constants.MINUTE]);
		} else {
			this._startCalendar.set(Calendar.HOUR_OF_DAY,
					timeInt[Constants.HOUR]);
			this._startCalendar
			.set(Calendar.MINUTE, timeInt[Constants.MINUTE]);
		}
	}

	public void modifyEndDateTime(int[] dateInt, int[] timeInt) {
		if (this._endCalendar == null) {
			this._endCalendar = Calendar.getInstance();
			this._endCalendar.clear();
			this._endCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY],
					timeInt[Constants.HOUR], timeInt[Constants.MINUTE]);
		} else {
			this._endCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY],
					timeInt[Constants.HOUR], timeInt[Constants.MINUTE]);
		}
	}

	public void modifyEndDate(int[] dateInt) {
		if (this._endCalendar == null) {
			this._endCalendar = Calendar.getInstance();
			this._endCalendar.set(Calendar.HOUR_OF_DAY, 0);
			this._endCalendar.clear(Calendar.MINUTE);
			this._endCalendar.clear(Calendar.SECOND);
			this._endCalendar.clear(Calendar.MILLISECOND);
			this._endCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY]);
		} else {
			this._endCalendar.set(dateInt[Constants.YEAR],
					dateInt[Constants.MONTH], dateInt[Constants.DAY]);
		}
	}

	public void modifyEndTime(int[] timeInt) {
		if (this._endCalendar == null) {
			this._endCalendar = Calendar.getInstance();
			this._endCalendar.clear(Calendar.YEAR);
			this._endCalendar.clear(Calendar.MONTH);
			this._endCalendar.clear(Calendar.DAY_OF_MONTH);
			this._endCalendar.set(Calendar.HOUR_OF_DAY,
					timeInt[Constants.HOUR]);
			this._endCalendar.set(Calendar.MINUTE, timeInt[Constants.MINUTE]);
		} else {
			this._endCalendar.set(Calendar.HOUR_OF_DAY,
					timeInt[Constants.HOUR]);
			this._endCalendar.set(Calendar.MINUTE, timeInt[Constants.MINUTE]);
		}
	}

	public void mark() {
		if (_taskStatus == Constants.TASK_STATUS.COMPLETED) {
			_taskStatus = Constants.TASK_STATUS.INCOMPLETE;
		} else {
			_taskStatus = Constants.TASK_STATUS.COMPLETED;
		}
	}

	public String getDescription() {
		return _description;
	}

	public Calendar getStartDate() {
		return _startCalendar;
	}

	public Calendar getEndDate() {
		return _endCalendar;
	}

	public boolean isCompleted() {
		if (this._taskStatus == Constants.TASK_STATUS.COMPLETED) {
			return true;
		} else {
			return false;
		}
	}

	public String getTaskStatusString() {
		if (this.isCompleted()) {
			return Constants.STRING_COMPLETED;
		} else {
			if (isOverdue()) {
				return Constants.STRING_OVERDUE;
			} else {
				return Constants.STRING_INCOMPLETE;
			}
		}
	}

	private boolean isOverdue() {
		if (this.getEndDate() == null) {
			return false;
		}

		Calendar now = Calendar.getInstance();

		int taskYear = this.getEndDate().get(Calendar.YEAR);
		int taskMonth = this.getEndDate().get(Calendar.MONTH)
				+ Constants.ADJUST_MONTH_BY_ONE;
		int taskDay = this.getEndDate().get(Calendar.DAY_OF_MONTH);
		int taskHour = this.getEndDate().get(Calendar.HOUR_OF_DAY);
		int taskMinute = this.getEndDate().get(Calendar.MINUTE);

		int nowYear = now.get(Calendar.YEAR);
		int nowMonth = now.get(Calendar.MONTH) + Constants.ADJUST_MONTH_BY_ONE;
		int nowDay = now.get(Calendar.DAY_OF_MONTH);
		int nowHour = now.get(Calendar.HOUR_OF_DAY);
		int nowMinute = now.get(Calendar.MINUTE);

		if (taskYear == Constants.DEFAULT_YEAR) {
			return false;
		}

		if (taskYear > nowYear) {
			return false;
		} else if (taskYear < nowYear) {
			return true;
		}

		if (taskMonth > nowMonth) {
			return false;
		} else if (taskMonth < nowMonth) {
			return true;
		}

		if (taskDay > nowDay) {
			return false;
		} else if (taskDay < nowDay) {
			return true;
		}

		if (taskHour == 0 && taskMinute == 0) {
			return false;
		}

		if (taskHour > nowHour) {
			return false;
		} else if (taskHour < nowHour) {
			return true;
		}

		if (taskMinute > nowMinute) {
			return false;
		} else if (taskMinute < nowMinute) {
			return true;
		}

		return true;
	}

	public boolean hasStartDate() {
		Calendar date = this.getStartDate();

		return !(date == null || !date.isSet(Calendar.DAY_OF_MONTH)
				|| date.get(Calendar.YEAR) == Constants.DEFAULT_YEAR || date
				.get(Calendar.YEAR) == 0
				&& date.get(Calendar.MONTH) == 0
				&& date.get(Calendar.DAY_OF_MONTH) == 0);
	}

	public boolean hasEndDate() {
		Calendar date = this.getEndDate();

		return !(date == null || !date.isSet(Calendar.DAY_OF_MONTH)
				|| date.get(Calendar.YEAR) == Constants.DEFAULT_YEAR || date
				.get(Calendar.YEAR) == 0
				&& date.get(Calendar.MONTH) == 0
				&& date.get(Calendar.DAY_OF_MONTH) == 0);
	}

	public boolean hasStartTime() {
		Calendar date = this.getStartDate();

		return !(date == null || !date.isSet(Calendar.HOUR_OF_DAY) || date
				.get(Calendar.HOUR_OF_DAY) == 0
				&& date.get(Calendar.MINUTE) == 0);
	}

	public boolean hasEndTime() {
		Calendar date = this.getEndDate();

		return !(date == null || !date.isSet(Calendar.HOUR_OF_DAY) || date
				.get(Calendar.HOUR_OF_DAY) == 0
				&& date.get(Calendar.MINUTE) == 0);
	}

	public String getStartDateString() {
		if (hasStartDate()) {
			Calendar cal = this.getStartDate();

			if (cal.get(Calendar.YEAR) == Constants.DEFAULT_YEAR) {
				return Constants.NO_START_DATE;
			} else {
				int day = cal.get(Calendar.DAY_OF_MONTH);
				int month = cal.get(Calendar.MONTH)
						+ Constants.ADJUST_MONTH_BY_ONE;
				int year = cal.get(Calendar.YEAR)
						- Constants.TWENTY_FIRST_CENTURY;
				return String.format(Constants.FORMAT_DATE_STRING, day, month,
						year);
			}
		} else {
			return Constants.NO_START_DATE;
		}
	}

	public String getEndDateString() {
		if (hasEndDate()) {
			Calendar cal = this.getEndDate();

			if (cal.get(Calendar.YEAR) == Constants.DEFAULT_YEAR) {
				return Constants.NO_END_DATE;
			} else {
				int day = cal.get(Calendar.DAY_OF_MONTH);
				int month = cal.get(Calendar.MONTH)
						+ Constants.ADJUST_MONTH_BY_ONE;
				int year = cal.get(Calendar.YEAR)
						- Constants.TWENTY_FIRST_CENTURY;
				return String.format(Constants.FORMAT_DATE_STRING, day, month,
						year);
			}
		} else {
			return Constants.NO_END_DATE;
		}
	}

	public String getStartDateStringNoSlash() {
		if (hasStartDate()) {
			Calendar cal = this.getStartDate();

			return String.format(Constants.FORMAT_DATE_STRING_NO_SLASH,
					cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH)
					+ Constants.ADJUST_MONTH_BY_ONE,
					cal.get(Calendar.YEAR));
		} else {
			return Constants.NO_START_DATE;
		}
	}
	
	public String getStartDateStringNoSlashModify() {
		if (hasStartDate()) {
			Calendar cal = this.getStartDate();

			return String.format(Constants.FORMAT_DATE_STRING_NO_SLASH,
					cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH)
					+ Constants.ADJUST_MONTH_BY_ONE,
					cal.get(Calendar.YEAR) - Constants.TWENTY_FIRST_CENTURY);
		} else {
			return Constants.NO_START_DATE;
		}
	}

	public String getEndDateStringNoSlash() {
		if (hasEndDate()) {
			Calendar cal = this.getEndDate();

			return String.format(Constants.FORMAT_DATE_STRING_NO_SLASH,
					cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH),
					cal.get(Calendar.YEAR));
		} else {
			return Constants.NO_END_DATE;
		}
	}
	
	public String getEndDateStringNoSlashModify() {
		if (hasEndDate()) {
			Calendar cal = this.getEndDate();
			
			return String.format(Constants.FORMAT_DATE_STRING_NO_SLASH,
					cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH),
					cal.get(Calendar.YEAR) - Constants.TWENTY_FIRST_CENTURY);
		} else {
			return Constants.NO_END_DATE;
		}
	}

	public String getStartTimeString() {
		if (hasStartTime()) {
			Calendar startCal = this.getStartDate();

			return String.format("%02d", startCal.get(Calendar.HOUR_OF_DAY))
					+ ":"
					+ String.format("%02d", startCal.get(Calendar.MINUTE));
		} else {
			return Constants.NO_START_TIME;
		}
	}

	public String getEndTimeString() {
		if (hasEndTime()) {
			Calendar endCal = this.getEndDate();

			return String.format("%02d", endCal.get(Calendar.HOUR_OF_DAY))
					+ ":" + String.format("%02d", endCal.get(Calendar.MINUTE));
		} else {
			return Constants.NO_END_TIME;
		}
	}

}
